package com.platform.utils.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.platform.exception.SerializerException;

import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;


/**
 * Class description goes here.
 *
 * @version：2016年11月19日 上午1:59:38
 * @author：udkylin
 */
public class JsonSerializeUtil {
	@SuppressWarnings("rawtypes")
	private static ConcurrentHashMap objWriterCache = new ConcurrentHashMap();
	@SuppressWarnings("rawtypes")
	private static ConcurrentHashMap objWriterCacheNoType = new ConcurrentHashMap();
	@SuppressWarnings("rawtypes")
	private static ConcurrentHashMap objWriterCacheNoNull = new ConcurrentHashMap();
	private static ObjectMapper mapper = new ObjectMapper();
	private static ObjectMapper mapperNoType = new ObjectMapper();
	private static ObjectMapper mapperNoNull = new ObjectMapper();

	@SuppressWarnings("unchecked")
	private static ObjectWriter getObjWriter(Class<?> serializationView) {
		if (objWriterCache.get(serializationView) != null) {
			return (ObjectWriter) objWriterCache.get(serializationView);
		}
		ObjectWriter temp = mapper.writerWithView(serializationView);
		objWriterCache.put(serializationView, temp);
		return temp;
	}

	@SuppressWarnings("unchecked")
	private static ObjectWriter getObjWriterNoType(Class<?> serializationView) {
		if (objWriterCacheNoType.get(serializationView) != null) {
			return (ObjectWriter) objWriterCacheNoType.get(serializationView);
		}
		ObjectWriter temp = mapperNoType.writerWithView(serializationView);
		objWriterCacheNoType.put(serializationView, temp);
		return temp;
	}

	@SuppressWarnings("unchecked")
	private static ObjectWriter getObjWriterNoNull(Class<?> serializationView) {
		if (objWriterCacheNoNull.get(serializationView) != null) {
			return (ObjectWriter) objWriterCacheNoNull.get(serializationView);
		}
		mapperNoNull.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		ObjectWriter temp = mapperNoNull.writerWithView(serializationView);
		objWriterCacheNoNull.put(serializationView, temp);
		return temp;
	}

	public static String jsonSerializer(Object originalObject) {
		try {
			mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
			ObjectWriter objectWriter = getObjWriter(originalObject.getClass());
			return objectWriter.writeValueAsString(originalObject);
		} catch (Exception e) {
			throw new SerializerException(
					String.format("对象%s序列化失败。", new Object[] { originalObject.getClass().getName() }), e);
		}
	}

	public static String jsonSerializerNoType(Object originalObject) {
		try {
			ObjectWriter objectWriter = getObjWriterNoType(originalObject.getClass());
			return objectWriter.writeValueAsString(originalObject);
		} catch (Exception e) {
			throw new SerializerException(
					String.format("对象%s序列化失败。", new Object[] { originalObject.getClass().getName() }), e);
		}
	}

	public static String jsonSerializerNoNull(Object originalObject) {
		try {
			ObjectWriter objectWriter = getObjWriterNoNull(originalObject.getClass());
			return objectWriter.writeValueAsString(originalObject);
		} catch (Exception e) {
			throw new SerializerException(
					String.format("对象%s序列化失败。", new Object[] { originalObject.getClass().getName() }), e);
		}
	}

	@SuppressWarnings("deprecation")
	public static <T> T jsonReSerializer(String jsonStr, Class<T> calzz) {
		try {
			mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
			ObjectReader reader = mapper.reader(calzz);
			return reader.readValue(jsonStr);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	@SuppressWarnings("deprecation")
	public static <T> T jsonReSerializerNoType(String jsonStr, Class<T> calzz) {
		try {
			ObjectReader reader = mapperNoType.reader(calzz);
			return reader.readValue(jsonStr);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	@SuppressWarnings("deprecation")
	public static <T> T jsonReSerializerNoNull(String jsonStr, Class<T> calzz) {
		try {
			ObjectReader reader = mapperNoNull.reader(calzz);
			return reader.readValue(jsonStr);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	@SuppressWarnings("deprecation")
	public static <T> T jsonReSerializerNoType(String jsonStr, Type type) {
		try {
			ObjectReader reader = mapperNoType.reader(TypeFactory.defaultInstance().constructType(type));
			return reader.readValue(jsonStr);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	@SuppressWarnings("deprecation")
	public static <T> T jsonReSerializerNoType(String jsonStr, TypeReference<T> typeReference) {
		try {
			ObjectReader reader = mapperNoType.reader(typeReference);
			return reader.readValue(jsonStr);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	public static <T, P> T jsonReSerializerNoType(String jsonStr, Class<T> type, Class<P> parametric) {
		try {
			JavaType t = mapperNoType.getTypeFactory().constructParametricType(type, new Class[] { parametric });
			return mapperNoType.readValue(jsonStr, t);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	public static <T, P> T jsonReSerializerNest(String jsonStr, Class<T> type, Class<P>[] parametric) {
		try {
			JavaType t = getJacaType(type, parametric);
			return mapperNoType.readValue(jsonStr, t);
		} catch (Exception e) {
			throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", new Object[] { jsonStr }), e);
		}
	}

	private static <T, P> JavaType getJacaType(Class<T> cls, Class<P>[] parametric) {
		if ((parametric == null) || (parametric.length == 0)) {
			throw new SerializerException(String.format("序列化方法调用错误导致字符串反序列化失败，请确认！", new Object[0]), null);
		}
		if (parametric.length == 1) {
			return mapperNoType.getTypeFactory().constructParametricType(cls, new Class[] { parametric[0] });
		}
		JavaType type = null;
		for (int i = parametric.length; i >= 2; i--) {
			if (type == null) {
				type = mapperNoType.getTypeFactory().constructParametricType(parametric[(i - 2)],
						new Class[] { parametric[(i - 1)] });
			} else if (i <= parametric.length - 2) {
				type = mapperNoType.getTypeFactory().constructParametricType(parametric[(i - 1)],
						new JavaType[] { type });
			}
		}
		return mapperNoType.getTypeFactory().constructParametricType(cls, new JavaType[] { type });
	}
	
	/**
     * 根据传入Class类型反序列化不带类型的json串
     * 
     * @param jsonStr
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T reSerializerNoType(String jsonStr, Class<T> clazz) {
        try {
            if (jsonStr == null) {
                return null;
            }
            if (clazz == String.class) {
                return (T)jsonStr;
            }
            ObjectReader reader = mapperNoType.readerFor(clazz);
            T object = reader.readValue(jsonStr);
            return object;
        } catch (Exception e) {
            throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", jsonStr), e);
        }
    }
    
    /**
     * 根据Type去反序列化，适用于有泛型的对象
     * 
     * @param jsonStr
     * @param type
     * @return
     */
    @SuppressWarnings("unchecked")
	public static <T> T reSerializerNoType(String jsonStr, Type type) {
        try {
            if (jsonStr == null) {
                return null;
            }
            if (type == String.class) {
                return (T)jsonStr;
            }
            ObjectReader reader = mapperNoType.readerFor(TypeFactory.defaultInstance().constructType(type));
            T object = reader.readValue(jsonStr);
            return object;
        } catch (Exception e) {
            throw new SerializerException(String.format("字符串[%.20s]...反序列化失败。", jsonStr), e);
        }
    }
    
    public static String serializerNoType(Object originalObject) {
        try {
            if (originalObject == null) {
                return null;
            }
            if (originalObject instanceof String) {
                return (String)originalObject;
            }
            ObjectWriter objectWriter = getObjWriterNoType(originalObject.getClass());
            String json = objectWriter.writeValueAsString(originalObject);
            return json;
        } catch (Exception e) {
            throw new SerializerException(String.format("对象%s序列化失败。", originalObject.getClass().getName()), e);
        }
    }
}
